/**
 * @author : andy
 * @description : stomp订阅消息类
 */
import { Client , type IFrame, type IMessage, type IPublishParams, type StompConfig, type StompSubscription } from '@stomp/stompjs';
import { omit } from 'lodash-es';
export interface StompParams extends StompConfig {
  /** 重连次数 */
  reconnectCount?: number;
  /** 是否需要重连 */
  needReconnect?: boolean;
}
export type MessageCallback = (message: IMessage) => void;
export default class Stomp {
  /** stomp实例唯一标识 */
  id: string;
  /** stomp实例 */
  private stomp: Client;
  /** 创建stomp实例参数 */
  private params: StompParams;
  /** 重连次数 */
  private reconnectCount: number = 0;
  /** 订阅消息回调集合 */
  private queueToReceiveCallback: Map<string , MessageCallback> = new Map();
  /** 发送消息参数 */
  private sendParams?: IPublishParams;
  /** 停止订阅消息集合 */
  private queueToStopReceive: Map<string , StompSubscription> = new Map();
  constructor (params: StompParams) {
    this.id = Date.now().toString(16);
    this.params = {
      needReconnect : true,
      reconnectCount : 5,
      ...params
    };
    const defaultConfig: StompConfig = {
      reconnectDelay : 5000,
      heartbeatIncoming : 4000,
      heartbeatOutgoing : 4000
    }
    const config: StompConfig = omit({...defaultConfig , ...params} , ['reconnectCount']);
    this.stomp = new Client(config);
    this.init();
    this.stomp.activate();
  }
  init () {
    // 连接成功后，监听队列消息，发送消息
    this.stomp.onConnect = () => {
      // 监听队列中的消息
      this._listen();
      // 发送消息
      this._send();
    }
    this.stomp.onStompError = (frame: IFrame) => {
      console.warn(`连接不上：${frame}`);
    }
    this.stomp.onWebSocketError = () => {
      // 当websocket连接不上时，如果启动了重连，那么会重连，超出指定的重连次数后，不会重连
      const { reconnectCount , needReconnect } = this.params;
      if (needReconnect) {
        if (reconnectCount && reconnectCount > 0) {
          this.reconnectCount++;
          if (this.reconnectCount >= reconnectCount) {
            this.stomp.deactivate();
          }
        } else {
          console.warn(`当启动重连时，必须要设置reconnectCount参数的值`);
        }
      } else {
        this.stomp.deactivate();
      }
    }
  }
  private _send () {
    if (this.sendParams) {
      this.stomp.publish({
        skipContentLengthHeader : true,
        ...this.sendParams
      })
    }
  }
  private _listen () {
    for (const queueName in this.queueToReceiveCallback) {
      const subscription = this.stomp.subscribe(queueName , (message: IMessage) => {
        const messageCallback = this.queueToReceiveCallback.get(queueName);
        if (messageCallback) {
          messageCallback(message);
        }
      })
      this.queueToStopReceive.set(queueName , subscription);
    }
  }
  /**
   * 订阅消息
   * @param queueName 消息主题名称
   * @param callback 订阅消息后的回调函数
   */
  subscribe (queueName: string , callback: MessageCallback) {
    this.queueToReceiveCallback.set(queueName , callback);
  }
  /**
   * 发送消息
   * @param options 发送消息参数
   */
  sendMessage (options: IPublishParams) {
    this.sendParams = options;
  }
  /**
   * 关闭连接，取消订阅消息
   */
  disconnect () {
    const queueNames = this.queueToStopReceive.keys();
    for (const queueName of queueNames) {
      this._stopMessage(queueName);
    }
    this.stomp.deactivate();
  }
  /**
   * 取消订阅消息
   * @param queueName 消息主题名称
   */
  private _stopMessage (queueName: string) {
    this.queueToStopReceive.get(queueName)?.unsubscribe();
  }
}